//
//  DODBObject.m
//  DOFramework
//
//  Created by 鞠 文杰 on 14-5-13.
//  Copyright (c) 2014年 dono. All rights reserved.
//  更新日志
//  20140515
//  增加全局变量
//  extern NSString *const kDOParsePropertiesTypeKey;
//  extern NSString *const kDOParseDatabaseTypeKey;
//  extern NSString *const kDOParsePropertiesSortedKey;
//
//  修复属性值对不上号问题
//  修改QueryAll等为类方法,设计合理性
//  增加KVO
//  带增加功能：可以设置类的transient属性值，即不保存到数据库
//

#import "DODBObject.h"
#import "DODBManager.h"
#import <objc/objc.h>
//模拟器用
//#import <objc/objc-runtime.h>
//真机用
#import <objc/runtime.h>
#import "DOConstants.h"
#import "NSString+DOTypeConvert.h"

@interface DODBObject ()
{
    NSString *tableName;
    
    NSString *delete;
    
    
    NSMutableArray *checkedTable;
    NSMutableString *create;
    NSMutableString *insert;
    NSMutableString *query;
    NSMutableString *update;
    
    NSMutableDictionary *keyDBTypes;
    NSDictionary *keyObjTypes;
    
    DODBManager *dbManager;
    
    @private
        NSInteger pk;
        BOOL isDirty;
        BOOL enableKVO;
}

@end




@implementation DODBObject

- (id)init
{
    self = [super init];
    if (self) {
        tableName = NSStringFromClass([self class]);
        dbManager = [DODBManager sharedSingleton];
        pk = -1;
        isDirty = NO;
        enableKVO = NO;
        [self buildSql];
//        [self addPropertiesObserver];
    }
    return self;
}

- (NSError *)save
{
    sqlite3 *db = [self database];
    sqlite3_stmt *stmt;
    NSError *err;
    
    //插入操作
    if (pk<0) {
        pk = [DODBManager primaryKeyWithClass:NSStringFromClass([self class])];
        
        if (sqlite3_prepare_v2(db, [insert UTF8String], -1, &stmt, nil) == SQLITE_OK) {
            NSString *type;
            NSString *name;
            NSArray *properties = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParsePropertiesSortedKey];
            int position = 1;
            sqlite3_bind_int(stmt, position++, pk);
            for (int i=0,len=properties.count; i<len; i++) {
                name = properties[i];
                type = [keyDBTypes objectForKey:name];
                if (type != nil) {
                    if ([[type lowercaseString] isEqualToString:@"integer"]) {
                        sqlite3_bind_int(stmt, position, [[self valueForKey:name] intValue]);
                    }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                        sqlite3_bind_double(stmt, position, [[self valueForKey:name] doubleValue]);
                    }else if([[type lowercaseString] isEqualToString:@"text"]){
                        sqlite3_bind_text(stmt, position, [[self valueForKey:name] UTF8String], -1, NULL);
                    }
                    else{
                        NSLog(@"%@ 类型暂未实现",type);
                    }
                    position ++;
                }
            }
            if (sqlite3_step(stmt) != SQLITE_DONE) {
                err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
            }
            sqlite3_finalize(stmt);
        }else{
            err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat: @"插入语句 <%@> 错误，请检查",insert]}];
        }
    }else{
        if (isDirty) {
            //update op
            if (sqlite3_prepare_v2(db, [update UTF8String], -1, &stmt, nil) == SQLITE_OK) {
                NSString *type;
                NSString *name;
                NSArray *properties = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParsePropertiesSortedKey];
                int position = 1;
                for (int i=0,len=properties.count; i<len; i++) {
                    name = properties[i];
                    type = [keyDBTypes objectForKey:name];
                    if (type != nil) {
                        if ([[type lowercaseString] isEqualToString:@"integer"]) {
                            sqlite3_bind_int(stmt, position, [[self valueForKey:name] intValue]);
                        }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                            sqlite3_bind_double(stmt, position, [[self valueForKey:name] doubleValue]);
                        }else if([[type lowercaseString] isEqualToString:@"text"]){
                            sqlite3_bind_text(stmt, position, [[self valueForKey:name] UTF8String], -1, NULL);
                        }
                        else{
                            NSLog(@"%@ 类型暂未实现",type);
                        }
                        position ++;
                    }
                }
                sqlite3_bind_int(stmt, position, pk);
                if (sqlite3_step(stmt) != SQLITE_DONE) {
                    err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
                }
                sqlite3_finalize(stmt);
            }else{
                err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat:@"SQL语句<%@>错误，请检查",update]}];
            }
        }
    
    }
    return err;
}



- (NSError *)update
{
    return nil;
}

- (NSError *)deleteSelf
{
    if (pk<0) {
        return nil;
    }
    
    sqlite3 *db = [self database];
    NSString *deleteSql = [NSString stringWithFormat:@"%@ WHERE pk = ?",delete];

    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, [deleteSql UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        sqlite3_bind_int(stmt, 1, pk);
        if (sqlite3_step(stmt)!=SQLITE_DONE) {
            NSError *err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseDeleteError userInfo:@{@"error":[NSString stringWithFormat:@"删除错误 <%@>",deleteSql]}];
            return err;
        }
    }else{
       //sql error
    }
    
    sqlite3_finalize(stmt);
    return nil;
}

+ (void)removeAll
{
    [self chekcTable];
    [self updateTable:[NSString stringWithFormat:@"DELETE FROM %@",NSStringFromClass([self class])]];
}

+ (NSArray *)allObjects
{
    [self chekcTable];
    NSMutableArray *result = [NSMutableArray array];
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *query = [classInfo objectForKey:@"query"];
    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSArray *soretdProperties = [classInfo objectForKeyedSubscript:kDOParsePropertiesSortedKey];
    if (sqlite3_prepare_v2(db, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        id model;
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            model = [[[self class] alloc] init];
            NSString *type;
            NSString *name;
            int position = 0;
            //            [model setValue:[NSNumber numberWithInt:sqlite3_column_int(stmt, position++)] forKey:@"pk"];
            [model setPK:sqlite3_column_int(stmt, position++)];
            for (int i=0,len=soretdProperties.count; i<len; i++) {
                name = soretdProperties[i];
                type = [dbTypes objectForKey:name];
                if (type != nil) {
                    if ([[type lowercaseString] isEqualToString:@"integer"]
                        || [[type lowercaseString] isEqualToString:@"double"]
                        || [[type lowercaseString ] isEqualToString:@"float"]) {
                        [model setValue:[NSNumber numberWithInt: sqlite3_column_int(stmt, position)] forKey:name];
                    }else if([[type lowercaseString] isEqualToString:@"text"]){
                        const char *columnValue =(char *) sqlite3_column_text(stmt, position);
                        columnValue = (columnValue == NULL)?"":columnValue;
                        [model setValue:[NSString stringWithUTF8String:columnValue] forKey:name];
                    }
                    else{
                        NSLog(@"%@ 类型暂未实现",type);
                    }
                    position ++;
                }
            }
            [model addPropertiesObserver];
//            [model performSelector:@selector(addPropertiesObserver) withObject:nil];
            [result addObject:model];
        }
        sqlite3_finalize(stmt);
    }
    return result;
}

+ (NSError *)saveObjects:(NSArray *)objects
{
    [self chekcTable];
    NSError *err;
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *insertTmp = [classInfo objectForKey:@"insert"];
    NSString *updateTmp = [classInfo objectForKey:@"update"];
    NSArray *properties = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParsePropertiesSortedKey];
    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSInteger pkTmp;
    NSString *classname = NSStringFromClass(self);
    for (id model in objects) {
        pkTmp = [model pk];
        
        if (pkTmp<0) {
            pkTmp = [DODBManager primaryKeyWithClass:classname];
            if (sqlite3_prepare_v2(db, [insertTmp UTF8String], -1, &stmt, nil) == SQLITE_OK) {
                NSString *type;
                NSString *name;
                
                int position = 1;
                sqlite3_bind_int(stmt, position++, pkTmp);
                for (int i=0,len=properties.count; i<len; i++) {
                    name = properties[i];
                    type = [dbTypes objectForKey:name];
                    if (type != nil) {
                        if ([[type lowercaseString] isEqualToString:@"integer"]) {
                            sqlite3_bind_int(stmt, position, [[model valueForKey:name] intValue]);
                        }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                            sqlite3_bind_double(stmt, position, [[model valueForKey:name] doubleValue]);
                        }else if([[type lowercaseString] isEqualToString:@"text"]){
                            sqlite3_bind_text(stmt, position, [[model valueForKey:name] UTF8String], -1, NULL);
                        }
                        else{
                            NSLog(@"%@ 类型暂未实现",type);
                        }
                        position ++;
                    }
                }
                if (sqlite3_step(stmt) != SQLITE_DONE) {
                    err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
                }
            }else{
                err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat: @"插入语句 <%@> 错误，请检查",insertTmp]}];
            }
            sqlite3_finalize(stmt);
        }else{
            //update
            BOOL dirty = [model isDirty];
            if (dirty) {
                if (sqlite3_prepare_v2(db, [updateTmp UTF8String], -1, &stmt, nil) == SQLITE_OK) {
                    NSString *type;
                    NSString *name;
                    int position = 1;
                    for (int i=0,len=properties.count; i<len; i++) {
                        name = properties[i];
                        type = [dbTypes objectForKey:name];
                        if (type != nil) {
                            if ([[type lowercaseString] isEqualToString:@"integer"]) {
                                sqlite3_bind_int(stmt, position, [[model valueForKey:name] intValue]);
                            }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                                sqlite3_bind_double(stmt, position, [[model valueForKey:name] doubleValue]);
                            }else if([[type lowercaseString] isEqualToString:@"text"]){
                                sqlite3_bind_text(stmt, position, [[model valueForKey:name] UTF8String], -1, NULL);
                            }
                            else{
                                NSLog(@"%@ 类型暂未实现",type);
                            }
                            position ++;
                        }
                    }
                    sqlite3_bind_int(stmt, position, pkTmp);
                    if (sqlite3_step(stmt) != SQLITE_DONE) {
                        err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
                    }
                    sqlite3_finalize(stmt);
                }else{
                    err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat:@"SQL语句<%@>错误，请检查",updateTmp]}];
                }
                sqlite3_finalize(stmt);
            }
        }
    }
    
    return err;
}

+ (NSError *)saveObjects1:(NSArray *)objects
{
    [self chekcTable];
    NSError *err;
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *insertTmp = [classInfo objectForKey:@"insert"];
    NSString *updateTmp = [classInfo objectForKey:@"update"];
    NSArray *properties = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParsePropertiesSortedKey];
    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSInteger pkTmp;
    NSMutableString *pkQuery = [NSMutableString stringWithFormat:@"SELECT SEQ FROM PKSEQ WHERE NAME = '%@'",NSStringFromClass([self class])];
//    NSString *classname = NSStringFromClass(self);
    for (id model in objects) {
        pkTmp = [model pk];
        
        if (pkTmp<0) {
            //insert
            
            char *errmsg = NULL;
            //查询和更新主键
            const char *queryChar = [pkQuery UTF8String];
            if (sqlite3_prepare_v2(db, queryChar, -1, &stmt, nil) == SQLITE_OK) {
                if (sqlite3_step(stmt) == SQLITE_ROW) {
                    pkTmp = sqlite3_column_int(stmt, 0) + 1;
                    //更新表内序号
                    NSString *pkIncSQL = [NSString stringWithFormat:@"UPDATE PKSEQ SET SEQ=%d WHERE NAME='%@'",pkTmp,NSStringFromClass([self class])];
                    if (sqlite3_exec(db, [pkIncSQL UTF8String], NULL, NULL, &errmsg)) {
                        NSLog(@"增加%@的主键失败!",NSStringFromClass([model class]));
                    }
                }
            }
            if (sqlite3_prepare_v2(db, [insertTmp UTF8String], -1, &stmt, nil) == SQLITE_OK) {
                NSString *type;
                NSString *name;
                
                int position = 1;
                sqlite3_bind_int(stmt, position++, pkTmp);
                for (int i=0,len=properties.count; i<len; i++) {
                    name = properties[i];
                    type = [dbTypes objectForKey:name];
                    if (type != nil) {
                        if ([[type lowercaseString] isEqualToString:@"integer"]) {
                            sqlite3_bind_int(stmt, position, [[model valueForKey:name] intValue]);
                        }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                            sqlite3_bind_double(stmt, position, [[model valueForKey:name] doubleValue]);
                        }else if([[type lowercaseString] isEqualToString:@"text"]){
                            sqlite3_bind_text(stmt, position, [[model valueForKey:name] UTF8String], -1, NULL);
                        }
                        else{
                            NSLog(@"%@ 类型暂未实现",type);
                        }
                        position ++;
                    }
                }
                if (sqlite3_step(stmt) != SQLITE_DONE) {
                    err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
                }
                                sqlite3_free(errmsg);
                
            }else{
                err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat: @"插入语句 <%@> 错误，请检查",insertTmp]}];
            }
            sqlite3_finalize(stmt);
        }else{
            //update
            BOOL dirty = [model isDirty];
            if (dirty) {
                if (sqlite3_prepare_v2(db, [updateTmp UTF8String], -1, &stmt, nil) == SQLITE_OK) {
                    NSString *type;
                    NSString *name;
                    int position = 1;
                    for (int i=0,len=properties.count; i<len; i++) {
                        name = properties[i];
                        type = [dbTypes objectForKey:name];
                        if (type != nil) {
                            if ([[type lowercaseString] isEqualToString:@"integer"]) {
                                sqlite3_bind_int(stmt, position, [[model valueForKey:name] intValue]);
                            }else if([[type lowercaseString]isEqualToString:@"double"] || [[type lowercaseString] isEqualToString:@"float"] ){
                                sqlite3_bind_double(stmt, position, [[model valueForKey:name] doubleValue]);
                            }else if([[type lowercaseString] isEqualToString:@"text"]){
                                sqlite3_bind_text(stmt, position, [[model valueForKey:name] UTF8String], -1, NULL);
                            }
                            else{
                                NSLog(@"%@ 类型暂未实现",type);
                            }
                            position ++;
                        }
                    }
                    sqlite3_bind_int(stmt, position, pkTmp);
                    if (sqlite3_step(stmt) != SQLITE_DONE) {
                        err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":@"SQL绑定数据错误，请检查"}];
                    }
                    sqlite3_finalize(stmt);
                }else{
                    err = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseInsertError userInfo:@{@"error":[NSString stringWithFormat:@"SQL语句<%@>错误，请检查",updateTmp]}];
                }
                sqlite3_finalize(stmt);
            }
        }
    }
    
    return err;
}


+ (NSArray *)queryByPage:(int)page
                andLimit:(int)limit
{
    [self chekcTable];
    NSMutableArray *result = [NSMutableArray array];
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *query = [[classInfo objectForKey:@"query"] stringByAppendingFormat:@" limit %d offset %d",limit,page*limit];

    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSArray *soretdProperties = [classInfo objectForKeyedSubscript:kDOParsePropertiesSortedKey];
    if (sqlite3_prepare_v2(db, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        id model;
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            model = [[[self class] alloc] init];
            NSString *type;
            NSString *name;
            int position = 0;
            //            [model setValue:[NSNumber numberWithInt:sqlite3_column_int(stmt, position++)] forKey:@"pk"];
            [model setPK:sqlite3_column_int(stmt, position++)];
            for (int i=0,len=soretdProperties.count; i<len; i++) {
                name = soretdProperties[i];
                type = [dbTypes objectForKey:name];
                if (type != nil) {
                    if ([[type lowercaseString] isEqualToString:@"integer"]
                        || [[type lowercaseString] isEqualToString:@"double"]
                        || [[type lowercaseString ] isEqualToString:@"float"]) {
                        [model setValue:[NSNumber numberWithInt: sqlite3_column_int(stmt, position)] forKey:name];
                    }else if([[type lowercaseString] isEqualToString:@"text"]){
                        const char *columnValue =(char *) sqlite3_column_text(stmt, position);
                        columnValue = (columnValue == NULL)?"":columnValue;
                        [model setValue:[NSString stringWithUTF8String:columnValue] forKey:name];
                    }
                    else{
                        NSLog(@"%@ 类型暂未实现",type);
                    }
                    position ++;
                }
            }
            [model addPropertiesObserver];
            //            [model performSelector:@selector(addPropertiesObserver) withObject:nil];
            [result addObject:model];
        }
        sqlite3_finalize(stmt);
    }
    //sqlite3_close(db);
    return result;
}

+ (id)queryByPK:(NSInteger)pk
{
    if (pk<0) {
        return nil;
    }
    id model ;
    
    [self chekcTable];
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *query = [[classInfo objectForKey:@"query"] stringByAppendingFormat:@" where pk = %d",pk];
    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSArray *soretdProperties = [classInfo objectForKeyedSubscript:kDOParsePropertiesSortedKey];
    if (sqlite3_prepare_v2(db, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        id model;
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            model = [[[self class] alloc] init];
            NSString *type;
            NSString *name;
            int position = 0;
            //            [model setValue:[NSNumber numberWithInt:sqlite3_column_int(stmt, position++)] forKey:@"pk"];
            [model setPK:sqlite3_column_int(stmt, position++)];
            for (int i=0,len=soretdProperties.count; i<len; i++) {
                name = soretdProperties[i];
                type = [dbTypes objectForKey:name];
                if (type != nil) {
                    if ([[type lowercaseString] isEqualToString:@"integer"]
                        || [[type lowercaseString] isEqualToString:@"double"]
                        || [[type lowercaseString ] isEqualToString:@"float"]) {
                        [model setValue:[NSNumber numberWithInt: sqlite3_column_int(stmt, position)] forKey:name];
                    }else if([[type lowercaseString] isEqualToString:@"text"]){
                        const char *columnValue =(char *) sqlite3_column_text(stmt, position);
                        columnValue = (columnValue == NULL)?"":columnValue;
                        [model setValue:[NSString stringWithUTF8String:columnValue] forKey:name];
                    }
                    else{
                        NSLog(@"%@ 类型暂未实现",type);
                    }
                    position ++;
                }
            }
            [model addPropertiesObserver];
        }
        sqlite3_finalize(stmt);
    }
    
    return model;
}

//  20140914   ju   构建query时，连接前后增加一个空格
+ (NSArray *)queryBySQL:(NSString *)sql
{
    [self chekcTable];
    NSMutableArray *result = [NSMutableArray array];
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    NSDictionary *classInfo = [DODBManager infoWithClass:[self class]];
    sqlite3_stmt *stmt;
    NSString *query = [[classInfo objectForKey:@"query"] stringByAppendingFormat:@" %@",sql];
    
    NSDictionary *dbTypes = [classInfo objectForKey:kDOParseDatabaseTypeKey];
    NSArray *soretdProperties = [classInfo objectForKeyedSubscript:kDOParsePropertiesSortedKey];
    if (sqlite3_prepare_v2(db, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        id model;
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            model = [[[self class] alloc] init];
            NSString *type;
            NSString *name;
            int position = 0;
            //            [model setValue:[NSNumber numberWithInt:sqlite3_column_int(stmt, position++)] forKey:@"pk"];
            [model setPK:sqlite3_column_int(stmt, position++)];
            for (int i=0,len=soretdProperties.count; i<len; i++) {
                name = soretdProperties[i];
                type = [dbTypes objectForKey:name];
                if (type != nil) {
                    if ([[type lowercaseString] isEqualToString:@"integer"]
                        || [[type lowercaseString] isEqualToString:@"double"]
                        || [[type lowercaseString ] isEqualToString:@"float"]) {
                        [model setValue:[NSNumber numberWithInt: sqlite3_column_int(stmt, position)] forKey:name];
                    }else if([[type lowercaseString] isEqualToString:@"text"]){
                        const char *columnValue =(char *) sqlite3_column_text(stmt, position);
                        columnValue = (columnValue == NULL)?"":columnValue;
                        [model setValue:[NSString stringWithUTF8String:columnValue] forKey:name];
                    }
                    else{
                        NSLog(@"%@ 类型暂未实现",type);
                    }
                    position ++;
                }
            }
            [model addPropertiesObserver];
            //            [model performSelector:@selector(addPropertiesObserver) withObject:nil];
            [result addObject:model];
        }
        sqlite3_finalize(stmt);
    }
    //sqlite3_close(db);
    return result;

}

/**
 *  构造sql语句
 */
- (void)buildSql
{
        //assign from dic
    [[self class] chekcTable];
    NSDictionary *info = [DODBManager infoWithClass:[self class]];
    query = [info objectForKey:@"query"];
    create = [info objectForKey:@"create"];
    insert = [info objectForKey:@"insert"];
    delete = [info objectForKey:@"delete"];
    update = [info objectForKey:@"update"];
    keyDBTypes = [info objectForKey:kDOParseDatabaseTypeKey];
    keyObjTypes = [info objectForKey:kDOParsePropertiesTypeKey];
}

+ (void)buildSQL
{
    //generate key type map
    NSDictionary *propTypes = [self propertiesWithEncodedTypes];
    NSArray *sortedProps =
    [propTypes.allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSLiteralSearch];
    }];
    NSDictionary *dbTypes = [NSMutableDictionary dictionary];
    //convert to db types
    for (NSString *propName in sortedProps) {
        [dbTypes setValue:[[propTypes objectForKey:propName] toDBType] forKey:propName];
    }
    
    
    //generate sql
    NSMutableString *createTmp = [NSMutableString string];
    NSMutableString *insertTmp = [NSMutableString string];
    
    //20140515 增加
    NSMutableString *updateTmp = [NSMutableString string];
    NSMutableString *deleteTmp = [NSMutableString string];
    NSString *tablename = NSStringFromClass([self class]);
    
    NSMutableString *queryTmp = [NSMutableString stringWithString:@"SELECT pk ,"];
    [createTmp appendString:[NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (pk integer primary key,",tablename ] ];
    [insertTmp appendString:[NSString stringWithFormat:@"INSERT OR REPLACE INTO %@ (pk,",tablename]];
    
    [updateTmp appendString:[NSString stringWithFormat:@"UPDATE %@ SET ",tablename]];
    [deleteTmp appendString:[NSString stringWithFormat:@"DELETE FROM %@",tablename]];
    NSArray *dbType = sortedProps;
    NSString *type;
    NSString *name;
    NSMutableString *insertPosition = [NSMutableString string];
    [insertPosition appendString:@"(?,"];
    for (int i=0,len=dbType.count; i<len; i++) {
        name = dbType[i];
        type = [dbTypes objectForKey:name];
        if (type != nil) {
            [createTmp appendString:[NSString stringWithFormat:@"%@ %@",name,type]];
            [insertTmp appendString:name];
            [queryTmp appendString:name];
            [updateTmp appendString:[NSString stringWithFormat:@"%@=?",name]];
            [insertPosition appendString:@" ? "];
            if (i != len-1) {
                [createTmp appendString:@","];
                [insertTmp appendString:@","];
                [queryTmp appendString:@","];
                [insertPosition appendString:@","];
                [updateTmp appendString:@","];
            }else{
                [insertTmp appendString:@") VALUES"];
                [insertPosition appendString:@")"];
            }
        }
    }
    
    [insertTmp appendString:insertPosition];
    
    [createTmp appendString:@")"];
    [queryTmp appendString:[NSString stringWithFormat:@" FROM %@",NSStringFromClass([self class])]];
    [updateTmp appendString:@" WHERE PK=?"];
    
    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    [info setObject:insertTmp forKey:@"insert"];
    [info setObject:createTmp forKey:@"create"];
    [info setObject:queryTmp forKey:@"query"];
    [info setObject:updateTmp forKey:@"update"];
    [info setObject:deleteTmp forKey:@"delete"];
    
    [info setObject:propTypes forKey:kDOParsePropertiesTypeKey];
    [info setObject:dbTypes forKey:kDOParseDatabaseTypeKey];
    [info setObject:sortedProps forKey:kDOParsePropertiesSortedKey];
    [DODBManager registInMemoryWithClass:[self class] info:info];
}

+ (NSInteger)pkIndexFromDB
{
    [self chekcTable];
    NSInteger pk;
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    sqlite3_stmt *stmt;
    NSMutableString *query = [NSMutableString stringWithFormat:@"SELECT SEQ FROM PKSEQ WHERE NAME = '%@'",NSStringFromClass([self class])];
    if (sqlite3_prepare_v2(db, [query UTF8String], -1, &stmt, nil) == SQLITE_OK) {
        
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            pk = sqlite3_column_int(stmt, 0) + 1;
        }
        
        sqlite3_finalize(stmt);
    }
    //sqlite3_close(db);
    return pk;
}

+ (void)syncPkIndexToDB:(NSInteger)pk
{
    [self chekcTable];
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    
    char *errmsg = NULL;
    NSString *pkIncSQL = [NSString stringWithFormat:@"UPDATE PKSEQ SET SEQ=%d WHERE NAME='%@'",pk,NSStringFromClass([self class])];
    if (sqlite3_exec(db, [pkIncSQL UTF8String], NULL, NULL, &errmsg)) {
        NSLog(@"增加%@的主键失败!",NSStringFromClass([self class]));
    }

    sqlite3_free(errmsg);
}

- (sqlite3 *)database
{
    if (!dbManager) {
        dbManager = [DODBManager sharedSingleton];
    }
    return [dbManager database];
}

//+ (NSDictionary*)keyObjTypes
//{
//    if (!keyObjTypes) {
//        keyObjTypes = [[self class] propertiesWithEncodedTypes];
//        keyDBTypes = [NSMutableDictionary dictionary];
//        //convert to db types
//        for (NSString *propName in keyObjTypes.allKeys) {
//            [keyDBTypes setValue:[[keyObjTypes objectForKey:propName] toDBType] forKey:propName];
//        }
//    }
//    return keyObjTypes;
//}

+ (NSDictionary *)propertiesWithEncodedTypes
{
    NSLog(@"************");
    NSMutableDictionary *theProps;
    NSDictionary  *properties = [[DODBManager sharedSingleton] getClassProperties:[self class]];
    if (properties) {
        return properties;
    }
    if ([self superclass] != [DODBObject class])
        theProps = (NSMutableDictionary *)[[self superclass] propertiesWithEncodedTypes];
    else
        theProps = [NSMutableDictionary dictionary];
    
    unsigned int outCount;
    //if not define的缩写
    //测试 TARGET_OS_COCOTRON是否被定义
    //如果没有被定义
#ifndef TARGET_OS_COCOTRON
    objc_property_t *propList = class_copyPropertyList([self class], &outCount);
#else
    //	NSArray *propList = [cls getPropertiesList];
    NSArray *propList = [NSArray array];
    outCount = [propList count];
#endif
    int i;
    
    // Loop through properties and add declarations for the create
    for (i=0; i < outCount; i++)
    {
#ifndef TARGET_OS_COCOTRON
        objc_property_t oneProp = propList[i];
        NSString *propName = [NSString stringWithUTF8String:property_getName(oneProp)];
        NSString *attrs = [NSString stringWithUTF8String: property_getAttributes(oneProp)];
        // Read only attributes are assumed to be derived or calculated
        // See http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/chapter_8_section_3.html
        //只读属性不可修改
        //如果为可修改属性，设置property的属性类型
        if ([attrs rangeOfString:@",R,"].location == NSNotFound)
        {
            NSArray *attrParts = [attrs componentsSeparatedByString:@","];
            if (attrParts != nil)
            {
                if ([attrParts count] > 0)
                {
                    NSString *propType = [[attrParts objectAtIndex:0] substringFromIndex:1];
                    [theProps setObject:propType forKey:propName];
                }
            }
        }
#else
        NSArray *oneProp = [propList objectAtIndex:i];
        NSString *propName = [oneProp objectAtIndex:0];
        NSString *attrs = [oneProp objectAtIndex:1];
        [theProps setObject:attrs forKey:propName];
#endif
    }
    
#ifndef TARGET_OS_COCOTRON
    free( propList );
#endif
    
//        [[DODBManager sharedSingleton] registerInMemory:[self class] properties:theProps];
    return theProps;
//    }
}

//1、检查是否存在
//2、检查是否修改
//NSMutableArray *checkedTable;

+ (void)chekcTable
{
    
    if (![DODBManager existsClassInfo:[self class]]) {
//        [checkedTable addObject:[self class]];
        [self buildSQL];
        
        sqlite3 *db = [[DODBManager sharedSingleton] database];
        //执行create操作
        //查询表中所有字段和property比较，没有的添加进去
        char *errmsg = NULL;
        int result;
        if ((result = sqlite3_exec(db, [@"CREATE TABLE IF NOT EXISTS PKSEQ (name varchar(50) PRIMARY KEY,SEQ INTEGER)" UTF8String], NULL, NULL, &errmsg)) != SQLITE_OK) {
            NSLog(@"创建序列表错误:%s 错误代码:%d",errmsg,result);
        }
        
        if (sqlite3_exec(db, [[[DODBManager infoWithClass:[self class]] objectForKey:@"create"] UTF8String], NULL, NULL, &errmsg)!=SQLITE_OK) {
            NSAssert(NO, @"创建表失败");
        }
        
        NSMutableString *addSequenceSQL = [NSMutableString stringWithFormat:@"INSERT OR IGNORE INTO PKSEQ (name,seq) VALUES('%@',0)",NSStringFromClass([self class])];
        if (sqlite3_exec(db, [addSequenceSQL UTF8String], NULL, NULL, &errmsg)!=SQLITE_OK) {
            NSLog(@"初始化%@的pkseq失败",NSStringFromClass([self class]));
        }
        
        NSArray *tableCols = [self tableColumns];
        NSDictionary *dbTypes = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParseDatabaseTypeKey];
        NSArray *propNames = [[DODBManager infoWithClass:[self class]] objectForKey:kDOParsePropertiesSortedKey];
        for (NSString *propName in propNames) {
            //如果不包含新增列信息
            //修改表结构
            if (![tableCols containsObject:propName]) {
                [[self class ] updateTable:[NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ %@",[[self class] tableName],propName,[dbTypes objectForKey:propName]]];
            }
        }
        //解决errmsg导致内存泄露问题
        sqlite3_free(errmsg);
    }
    
}

/*
- (void)checkTable
{
    if (!checkedTable) {
        checkedTable = [NSMutableArray array];
    }
    if (![checkedTable containsObject:[self class]]) {
//        checkTableCount +=1;
        [checkedTable addObject:[self class]];


        sqlite3 *db = [[DODBManager sharedSingleton] database];
        //执行create操作
        //查询表中所有字段和property比较，没有的添加进去
        char *errmsg = NULL;
        
        if (sqlite3_exec(db, [@"CREATE TABLE IF NOT EXISTS PKSEQ (name varchar(50) PRIMARY KEY,SEQ INTEGER)" UTF8String], NULL, NULL, &errmsg) != SQLITE_OK) {
            NSLog(@"创建序列表错误:%s",errmsg);
        }
        
        if (sqlite3_exec(db, [create UTF8String], NULL, NULL, &errmsg)!=SQLITE_OK) {
            NSAssert(NO, @"创建表失败");
        }
        
        NSMutableString *addSequenceSQL = [NSMutableString stringWithFormat:@"INSERT OR IGNORE INTO PKSEQ (name,seq) VALUES('%@',0)",NSStringFromClass([self class])];
        if (sqlite3_exec(db, [addSequenceSQL UTF8String], NULL, NULL, &errmsg)!=SQLITE_OK) {
            NSLog(@"初始化%@的pkseq失败",NSStringFromClass([self class]));
        }
        
        NSArray *tableCols = [[self class ] tableColumns];
        NSArray *propNames = keyDBTypes.allKeys;
        for (NSString *propName in propNames) {
            //如果不包含新增列信息
            //修改表结构
            if (![tableCols containsObject:propName]) {
                needUpdateTable = YES;
                [[self class ] updateTable:[NSString stringWithFormat:@"ALTER TABLE %@ ADD COLUMN %@ %@",[[self class] tableName],propName,[keyDBTypes objectForKey:propName]]];
            }
        }
        
    }
    
    if (needUpdateTable) {
        [self buildSql];
    }
    
 
    static BOOL isFirst = YES;
    if (isFirst) {
        char *errMsg;
        if (sqlite3_exec(db, [create UTF8String], NULL, NULL, &errMsg) != SQLITE_OK) {
            sqlite3_close(db);
//            NSAssert(0, @"METAINFO表创建失败");
            return;
        }
        isFirst = NO;
        
    }
 
}
*/

+ (NSArray *)tableColumns
{
    NSMutableArray *cols = [NSMutableArray array];
    
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    //查询表的列信息
    NSString *queryCols = [NSString stringWithFormat:@"pragma table_info(%@)",NSStringFromClass([self class])];
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, [queryCols UTF8String],-1 , &stmt, nil) == SQLITE_OK) {
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            const unsigned char *colName = sqlite3_column_text(stmt, 1);
            NSString *colString = [NSString stringWithUTF8String:(const char*)colName];
            [cols addObject:colString];
        }
        sqlite3_finalize(stmt);
    }
    return cols;
}



+ (void)updateTable:(NSString*)sql
{
    sqlite3 *db = [[DODBManager sharedSingleton] database];
    char *errmsg = NULL;
    if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &errmsg) != SQLITE_OK) {
        NSString *err = [NSString stringWithFormat:@"执行语句 <%@> 错误",sql];
        NSAssert(0,err);
    }
    //解决errmsg导致内存泄露问题
    sqlite3_free(errmsg);
    //sqlite3_close(db);
}

- (void)addPropertiesObserver
{
    enableKVO = YES;
    for(NSString *propName in keyObjTypes.allKeys)
        [self addObserver:self forKeyPath:propName options:0 context:nil];
}

- (void)removePropertiesObserver
{
    if (enableKVO) {
        for(NSString *propName in keyObjTypes.allKeys){
            [self removeObserver:self forKeyPath:propName context:nil];
        }
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    isDirty = YES;
    NSLog(@"changed");

}

+ (NSString *)tableName
{
    return NSStringFromClass([self class]);
}

- (void)setPK:(int)_pk
{
    pk = _pk;
}

- (NSInteger)pk
{
    return pk;
}

- (BOOL)isDirty
{
    return isDirty;
}


- (void)dealloc
{
    [self removePropertiesObserver];
//    NSLog(@"dealloc");
}



@end
